package com.GB26875_3_2011.message;

import com.GB26875_3_2011.annotation.Handler;
import com.GB26875_3_2011.annotation.Parser;
import com.GB26875_3_2011.common.CommandType;
import com.GB26875_3_2011.common.GB26875Constant;
import com.GB26875_3_2011.config.ChannelManager;
import com.GB26875_3_2011.config.GB26875Properties;
import com.GB26875_3_2011.message.handler.MessageHandler;
import com.GB26875_3_2011.message.parser.MessageBodyParser;
import com.GB26875_3_2011.model.GB26875Message;
import com.GB26875_3_2011.model.GB26875MessageBody;
import com.GB26875_3_2011.util.ByteUtils;
import com.GB26875_3_2011.util.SpringUtils;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.util.Attribute;
import io.netty.util.AttributeKey;
import lombok.extern.slf4j.Slf4j;

import java.time.LocalDateTime;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;

/**
 * @author 蒋仕国
 * @projectName GB26875_3_211
 * @ClassName MessageParserContext
 * @date 2025-01-13 09:07
 * @Description: TODO []
 */
@Slf4j
public final class MessageContext {

    public static final Map<Integer, MessageBodyParser> PARSER_MAP = new ConcurrentHashMap<>();
    // commid --》 数据单元id -- 》 消息处理器
    public static final Map<Integer, Map<Integer, MessageHandler>> HANDLER_MAP = new ConcurrentHashMap<>();
    //消息流水号 存储到ChannelHandlerContext里面
    private static final AttributeKey<Integer> FLOW_ID = AttributeKey.newInstance("FlowId");

    //  主动下发的指令 key = deviceAddress + "-" + flowId
    private final static Map<String, SynchronousQueue<GB26875Message>> RESPONSE_MAP = new ConcurrentHashMap<>();
    // 人员信息表现
    private final static GB26875Properties gB26875Properties = SpringUtils.getBean(GB26875Properties.class);
    static {
        // 消息体parser处理
        Map<String, MessageBodyParser> beansOfType = SpringUtils.getBeansOfType(MessageBodyParser.class);
        beansOfType.forEach((beanName, bean) -> {
            Parser annotation = bean.getClass().getAnnotation(Parser.class);
            if (annotation != null) {
                if (PARSER_MAP.containsKey(annotation.unitId())) {
                    log.error("[重复注册Parser] {}", annotation.unitId());
                    throw new RuntimeException("[重复注册Parser] {}" + annotation.unitId());
                }
                PARSER_MAP.put(annotation.unitId(), bean);
            }
        });
        // 消息实际处理器
        Map<String, MessageHandler> beansOfType1 = SpringUtils.getBeansOfType(MessageHandler.class);
        beansOfType1.forEach((beanName, bean) -> {
            Handler annotation = bean.getClass().getAnnotation(Handler.class);
            if (annotation != null) {
                Map<Integer, MessageHandler> orDefault = HANDLER_MAP.getOrDefault(annotation.commandId(), new ConcurrentHashMap<>());
                if (orDefault.containsKey(annotation.unitId())) {
                    MessageHandler messageHandler = orDefault.get(annotation.unitId());
                    Handler resourceHandler =  messageHandler.getClass().getAnnotation(Handler.class);
                    if (annotation.order() >= resourceHandler.order()) {
                        orDefault.put(annotation.unitId(), bean);
                    }
                    log.error("[重复注册Handler] {},生效：{}", annotation.unitId(),messageHandler.getClass().getName());
                } else {
                    orDefault.put(annotation.unitId(), bean);
                }

                HANDLER_MAP.put(annotation.commandId(), orDefault);
            }
        });
    }

    public static String getLocalAddress() {
        return gB26875Properties.getLocalAddressHex();
    }

    public static String getProtocolVersion() {
        return gB26875Properties.getProtocolVersion();
    }

    /**
     * 获取消息解析器
     * @param msgId 消息Id
     * @return MessageBodyParser
     */
    public static MessageBodyParser getParser(int msgId) {
        MessageBodyParser messageBodyParser = PARSER_MAP.get(msgId);
        if (messageBodyParser != null) {
            return messageBodyParser;
        } else {
            log.error("没有找到对应的消息解析器，command:{}", msgId);
            return buffer -> {
                ByteUtils.readReadableBytes(buffer,true);
                return null;
            };
        }
    }

    /**
     * 获取消息处理器
     * @param commandId 命令ID
     * @param unitId 数据单元ID
     * @return
     */
    public static MessageHandler getHandler(Integer commandId, Integer unitId) {
        MessageHandler handler = null;
        Map<Integer, MessageHandler> integerMessageHandlerMap = HANDLER_MAP.get(commandId);
        if (integerMessageHandlerMap != null) {
            if (unitId == null && integerMessageHandlerMap.size() > 0) {
                handler = integerMessageHandlerMap.values().iterator().next();
            } else {
                handler = integerMessageHandlerMap.get(unitId);
            }
        }
        return handler != null ? handler : (msg) -> {
            System.out.println(msg);
            return confirm(msg);
        };
    }

    public static Integer getFlowId(Channel channel) {
        Attribute<Integer> flowIdAttr = channel.attr(FLOW_ID);
        Integer flowId = flowIdAttr.get();
        if (flowId == null) {
            flowId = 0;
        } else {
            flowId++;
        }
        flowIdAttr.set(flowId);
        return flowId;
    }

    public static void sendMessage(Channel channel, GB26875Message result) {
        channel.writeAndFlush(result).addListener(future -> {
            if (!future.isSuccess()) {
                log.error("[发送失败]", future.cause());
            }
        });
    }

    // 创建默认确认消息
    public static GB26875Message confirm(GB26875Message message) {
        GB26875Message result = new GB26875Message();
        result.setStartFlagHex(GB26875Constant.MESSAGE_START_FLAG_HEX).setEndFlagHex(GB26875Constant.MESSAGE_END_FLAG_HEX)
                .setFlowId(message.getFlowId())
                .setVersionHex(message.getVersionHex())
                .setTimeFlag(LocalDateTime.now())
                .setSourceAddressHex(message.getDestinationAddressHex())
                .setDestinationAddressHex(message.getSourceAddressHex())
                .setBodyLength((short) 0)
                .setCommandType(CommandType.COMMAND_03)
                .setMessageBody(new byte[0]);
        return result;

    }

    // 创建默认否认消息
    public static GB26875Message denied(GB26875Message message) {
        GB26875Message confirm = confirm(message);
        return confirm.setCommandType(CommandType.COMMAND_06);
    }


    /**
     * 创建任务消息数据
     * @param addressFlowId 目标设备address - 消息流水号
     */
    public static boolean buildQueue(String addressFlowId) {
        if (RESPONSE_MAP.containsKey(addressFlowId)) {
            return false;
        } else {
            RESPONSE_MAP.put(addressFlowId, new SynchronousQueue<>());
            return true;
        }
    }


    /**
     * 获取相应消息
     */
    public static GB26875Message getResponse(String addressFlowId, long timeout) {
        SynchronousQueue<GB26875Message> gb26875MessageSynchronousQueue = RESPONSE_MAP.get(addressFlowId);
        if (gb26875MessageSynchronousQueue != null) {
            GB26875Message gb26875Message = null;
            try {
                gb26875Message = gb26875MessageSynchronousQueue.poll(timeout, TimeUnit.MILLISECONDS);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return gb26875Message;
        }
        return null;
    }


    public static void putResponse(String addressFlowId, GB26875Message message) {
        if (RESPONSE_MAP.containsKey(addressFlowId)) {
            try {
                RESPONSE_MAP.get(addressFlowId).offer(message,1000,TimeUnit.MILLISECONDS);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }


    /**
     * 发送消息
     * @param message 消息内容
     * @param timeout 指定最大响应时间 【时间单位 {@link TimeUnit}】
     * @return
     */
    public static GB26875Message request(GB26875Message message,long timeout) {
        // 获取channel
        String destinationAddressHex = message.getDestinationAddressHex();
        Channel channel = ChannelManager.get(destinationAddressHex);
        if (channel == null) {
            log.error("[没有找到对应的channel] {}", destinationAddressHex);
            throw new RuntimeException("没有找到对应的channel");
        }
        Integer flowId = getFlowId(channel);
        // 流水号
        message.setFlowId(flowId.shortValue());
        // 本地地址
        message.setSourceAddressHex(getLocalAddress());
        // 软件版本
        message.setVersionHex(getProtocolVersion());
        if (buildQueue(destinationAddressHex + "-" + flowId)) {
            sendMessage(channel, message);
            return getResponse(destinationAddressHex + "-" + flowId, timeout);
        } else {
            log.error("[消息队列已存在] {}", destinationAddressHex + "-" + flowId);
            throw new RuntimeException("消息队列已存在");
        }
    }

}
